from __future__ import annotations

from math import ceil
from typing import Dict, List, Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_current_active_superuser
from app.core.database import get_db
from app.crud.crud_dictionary import dict_type as dict_type_crud, dict_data as dict_data_crud
from app.models.user import User
from app.schemas.base import UnifiedResponse, success_response
from app.schemas.dictionary import (
    DictTypeCreate,
    DictTypeUpdate,
    DictTypeInDB,
    DictTypeListResponse,
    DictDataCreate,
    DictDataUpdate,
    DictDataInDB,
    DictDataListResponse,
    DictBatchRequest,
    DictBatchResponse,
    DictBatchResponseItem,
    DictSortUpdateRequest,
)

router = APIRouter()


def _get_operator_name(user: User) -> str:
    return user.username or user.full_name or user.phone or user.email or str(user.id)


def _validate_status(value: Optional[str]) -> Optional[str]:
    if value is None:
        return None
    if value not in {"0", "1"}:
        raise HTTPException(status_code=400, detail="状态参数只允许 0 或 1")
    return value


@router.get("/types", response_model=UnifiedResponse[DictTypeListResponse])
async def list_dict_types(
    *,
    page: int = Query(1, ge=1, description="页码，从 1 开始"),
    page_size: int = Query(10, ge=1, le=100, description="每页数量"),
    status: Optional[str] = Query(None, description="状态过滤，0 正常 1 停用"),
    keyword: Optional[str] = Query(None, description="按名称或类型模糊搜索"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictTypeListResponse]:
    filter_status = _validate_status(status) if status is not None else None
    skip = (page - 1) * page_size
    items, total = await dict_type_crud.get_multi_with_filters(
        db,
        keyword=keyword,
        status=filter_status,
        skip=skip,
        limit=page_size,
    )
    total_pages = ceil(total / page_size) if total else 0
    payload = DictTypeListResponse(
        items=items,
        total=total,
        page=page,
        page_size=page_size,
        total_pages=total_pages,
    )
    return success_response(payload)


@router.get("/types/{dict_type}", response_model=UnifiedResponse[DictTypeInDB])
async def get_dict_type_detail(
    *,
    dict_type: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictTypeInDB]:
    dict_type_obj = await dict_type_crud.get_by_dict_type(db, dict_type=dict_type)
    if not dict_type_obj:
        raise HTTPException(status_code=404, detail="字典类型不存在")
    return success_response(dict_type_obj)


@router.post("/types", response_model=UnifiedResponse[DictTypeInDB])
async def create_dict_type(
    *,
    dict_type_in: DictTypeCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictTypeInDB]:
    existing = await dict_type_crud.get_by_dict_type(db, dict_type=dict_type_in.dict_type)
    if existing:
        raise HTTPException(status_code=400, detail="字典类型已存在")

    operator = _get_operator_name(current_user)
    dict_type_obj = await dict_type_crud.create_with_operator(
        db,
        obj_in=dict_type_in,
        operator=operator,
    )
    return success_response(dict_type_obj, msg="字典类型创建成功")


@router.put("/types/{dict_type}", response_model=UnifiedResponse[DictTypeInDB])
async def update_dict_type(
    *,
    dict_type: str,
    dict_type_in: DictTypeUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictTypeInDB]:
    dict_type_obj = await dict_type_crud.get_by_dict_type(db, dict_type=dict_type)
    if not dict_type_obj:
        raise HTTPException(status_code=404, detail="字典类型不存在")

    operator = _get_operator_name(current_user)
    dict_type_obj = await dict_type_crud.update_with_operator(
        db,
        db_obj=dict_type_obj,
        obj_in=dict_type_in,
        operator=operator,
    )
    return success_response(dict_type_obj, msg="字典类型更新成功")


@router.delete("/types/{dict_type}", response_model=UnifiedResponse[DictTypeInDB])
async def delete_dict_type(
    *,
    dict_type: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictTypeInDB]:
    dict_type_obj = await dict_type_crud.get_by_dict_type(db, dict_type=dict_type)
    if not dict_type_obj:
        raise HTTPException(status_code=404, detail="字典类型不存在")

    active_items = await dict_data_crud.get_items_by_type(db, dict_type=dict_type, status="0")
    if active_items:
        raise HTTPException(status_code=400, detail="请先停用或删除该类型下的字典数据")

    removed = await dict_type_crud.remove(db, id=str(dict_type_obj.id))
    return success_response(removed, msg="字典类型删除成功")


@router.get("/items", response_model=UnifiedResponse[DictDataListResponse])
async def list_dict_items(
    *,
    page: int = Query(1, ge=1, description="页码，从 1 开始"),
    page_size: int = Query(10, ge=1, le=100, description="每页数量"),
    dict_type: Optional[str] = Query(None, description="按字典类型过滤"),
    status: Optional[str] = Query(None, description="状态过滤，0 正常 1 停用"),
    keyword: Optional[str] = Query(None, description="按标签或键值模糊搜索"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictDataListResponse]:
    filter_status = _validate_status(status) if status is not None else None
    skip = (page - 1) * page_size
    items, total = await dict_data_crud.get_multi_with_filters(
        db,
        dict_type=dict_type,
        keyword=keyword,
        status=filter_status,
        skip=skip,
        limit=page_size,
    )
    total_pages = ceil(total / page_size) if total else 0
    payload = DictDataListResponse(
        items=items,
        total=total,
        page=page,
        page_size=page_size,
        total_pages=total_pages,
    )
    return success_response(payload)


@router.get("/{dict_type}/items", response_model=UnifiedResponse[List[DictDataInDB]])
async def get_dict_items_by_type(
    *,
    dict_type: str,
    status: Optional[str] = Query("0", description="状态过滤，0 正常 1 停用，留空为全部"),
    only_default: bool = Query(False, description="是否仅返回默认项"),
    db: AsyncSession = Depends(get_db),
) -> UnifiedResponse[List[DictDataInDB]]:
    filter_status = None if status in {None, "", "all"} else _validate_status(status)
    items = await dict_data_crud.get_items_by_type(
        db,
        dict_type=dict_type,
        status=filter_status,
    )
    if only_default:
        items = [item for item in items if item.is_default == "Y"]
    return success_response(items)


@router.post("/{dict_type}/items", response_model=UnifiedResponse[DictDataInDB])
async def create_dict_item(
    *,
    dict_type: str,
    dict_data_in: DictDataCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictDataInDB]:
    dict_type_obj = await dict_type_crud.get_by_dict_type(db, dict_type=dict_type)
    if not dict_type_obj:
        raise HTTPException(status_code=404, detail="字典类型不存在")

    existing = await dict_data_crud.get_by_value(
        db,
        dict_type=dict_type_obj.dict_type,
        dict_value=dict_data_in.dict_value,
    )
    if existing:
        raise HTTPException(status_code=400, detail="字典键值已存在")

    operator = _get_operator_name(current_user)
    dict_data_obj = await dict_data_crud.create_with_type(
        db,
        dict_type=dict_type_obj,
        obj_in=dict_data_in,
        operator=operator,
    )
    return success_response(dict_data_obj, msg="字典数据创建成功")


@router.put("/items/{item_id}", response_model=UnifiedResponse[DictDataInDB])
async def update_dict_item(
    *,
    item_id: str,
    dict_data_in: DictDataUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictDataInDB]:
    dict_data_obj = await dict_data_crud.get(db, id=item_id)
    if not dict_data_obj:
        raise HTTPException(status_code=404, detail="字典数据不存在")

    if (
        dict_data_in.dict_value is not None
        and dict_data_in.dict_value != dict_data_obj.dict_value
    ):
        existing = await dict_data_crud.get_by_value(
            db,
            dict_type=dict_data_obj.dict_type,
            dict_value=dict_data_in.dict_value,
            exclude_id=item_id,
        )
        if existing:
            raise HTTPException(status_code=400, detail="字典键值已存在")

    operator = _get_operator_name(current_user)
    dict_data_obj = await dict_data_crud.update_with_default(
        db,
        db_obj=dict_data_obj,
        obj_in=dict_data_in,
        operator=operator,
    )
    return success_response(dict_data_obj, msg="字典数据更新成功")


@router.delete("/items/{item_id}", response_model=UnifiedResponse[DictDataInDB])
async def delete_dict_item(
    *,
    item_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictDataInDB]:
    dict_data_obj = await dict_data_crud.get(db, id=item_id)
    if not dict_data_obj:
        raise HTTPException(status_code=404, detail="字典数据不存在")

    removed = await dict_data_crud.remove(db, id=item_id)
    return success_response(removed, msg="字典数据删除成功")


@router.put("/{dict_type}/items/sort", response_model=UnifiedResponse[DictBatchResponseItem])
async def update_dict_item_sort(
    *,
    dict_type: str,
    sort_in: DictSortUpdateRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_superuser),
) -> UnifiedResponse[DictBatchResponseItem]:
    dict_type_obj = await dict_type_crud.get_by_dict_type(db, dict_type=dict_type)
    if not dict_type_obj:
        raise HTTPException(status_code=404, detail="字典类型不存在")

    operator = _get_operator_name(current_user)
    for item in sort_in.items:
        dict_data_obj = await dict_data_crud.get(db, id=str(item.id))
        if not dict_data_obj or dict_data_obj.dict_type != dict_type_obj.dict_type:
            raise HTTPException(status_code=400, detail="存在无效的字典数据项")
        await dict_data_crud.update(
            db,
            db_obj=dict_data_obj,
            obj_in={"dict_sort": item.dict_sort, "update_by": operator},
        )

    items = await dict_data_crud.get_items_by_type(db, dict_type=dict_type_obj.dict_type)
    payload = DictBatchResponseItem(dict_type=dict_type_obj.dict_type, items=items)
    return success_response(payload, msg="排序更新成功")


@router.post("/batch", response_model=UnifiedResponse[DictBatchResponse])
async def batch_query_dicts(
    *,
    batch_in: DictBatchRequest,
    status: Optional[str] = Query("0", description="状态过滤，默认仅返回正常值"),
    db: AsyncSession = Depends(get_db),
) -> UnifiedResponse[DictBatchResponse]:
    filter_status = None if status in {None, "", "all"} else _validate_status(status)
    grouped = await dict_data_crud.get_batch_by_types(
        db,
        types=batch_in.types,
        status=filter_status,
    )

    items: List[DictBatchResponseItem] = [
        DictBatchResponseItem(dict_type=key, items=value)
        for key, value in grouped.items()
    ]
    return success_response(DictBatchResponse(items=items))
